<?php
namespace app\api\logic;

use app\api\cache\Marketing;
use app\api\consDir\ErrorConst;
use app\api\consDir\SupplyConst;
use app\api\services\CouponService;
use app\api\services\MemberService;
use app\api\services\SupplyService;
use app\common\libs\Singleton;
use app\common\models\Member\Address;
use app\common\models\Member\Collect;
use app\common\models\Order\Order;
use app\common\models\Order\OrderAddress;
use app\common\models\Order\OrderGoods;
use app\common\models\Supply\SupplyGoods;
use app\common\models\Supply\SupplySku;
use app\common\utils\CommonUtil;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Log;

class SupplyLogic extends BaseLogic
{
    use Singleton;

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function goodsCategory($categoryId): array
    {
        $info = SupplyService::getInstance()->goodsCategory($categoryId);
        return ['rows' => $info];
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function goodsList($page, $pageSize, $keyword, $categoryId1, $categoryId2, $categoryId3, $sort, $positionType = 0): array
    {
        $info = [];
        try {
            $info = SupplyService::getInstance()->goodsList(
                $page,
                $pageSize,
                $keyword,
                $categoryId1,
                $categoryId2,
                $categoryId3,
                $sort,
                $positionType
            );
            if ( ! empty($info)) {
                foreach ($info as &$v) {
                    $v['goodsImg']     = $v['coverImg'];
                    $v['gxz']          = bcmul($v['sellPrice'], bcmul($v['gxzRate'], 0.01, 4), 4);
                    $v['goodsTag']     = empty($v['goodsTag']) ? [] : json_decode($v['goodsTag'], true);
                    $v['goodsService'] = empty($v['goodsService']) ? [] : json_decode($v['goodsService'], true);
                }
            }
        } catch (\Exception $e) {
            // echo $e->getMessage();
        }

        return ['rows' => $info];
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function goodsDetail($id): array
    {
        $info = SupplyService::getInstance()->goodsDetail($id);
        if (empty($info)) {
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, ErrorConst::PARAM_ERROR_MSG);
        }
        $ret = SupplyService::getInstance()->getData(SupplyConst::GET_SPU_BY_SPUIDS, ['spuIdList' => [$info['spuId']]]);
        if ($ret['status'] != 200 || empty($ret['data'])) {
            SupplyGoods::getInstance()->where('id', $id)->update(['status' => 1]);
            CommonUtil::throwException(ErrorConst::NO_GOODS_ERROR, ErrorConst::NO_GOODS_ERROR_MSG);
        }
        $field = [
            'id',
            'sku_id',
            'sku_pic_url',
            'status',
            'buy_start_qty',
            'stock',
            'suggest_price',
            'official_distri_price',
            'sku_property_list',
            'spu_id',
            'goods_sales',
        ];
        $skuList                 = SupplySku::getInstance()->field($field)->where('spu_id', $info['spuId'])->select() ?: [];
        $info['skuList']         = $skuList;
        $info['gxz']             = bcmul($info['sellPrice'], bcmul($info['gxzRate'], 0.01, 4), 4);
        $info['carouselImgList'] = json_encode($info['carouselImgList']);
        //收藏
        $where = [
            'collect_id' => $id,
            'type'       => 4,
            'user_id'    => $this->userinfo->id,
        ];
        $info['isCollect'] = (bool) Collect::getInstance()->where($where)->value('id');
        $info['spuId']     = strval($info['spuId']);
        return $info;
    }

    public function getRegionByCodeOpen($regionCode): array
    {
        $info = SupplyService::getInstance()->getRegionByCodeOpen($regionCode);
        return ['rows' => $info];
    }

    public function getOrderDetail($orderSn): array
    {
        return SupplyService::getInstance()->getOrderDetail($orderSn);
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function orderPreview($spuInfoList, $addressId): array
    {
        [$level_discount, $coupon_discount_both] = \app\api\services\UserLevelService::getInstance()->levelDiscount(
            $this->userinfo->id
        );
        // var_dump($level_discount);exit;
        $address = Address::getInstance()->where('id', $addressId)->find();
        //获取商品运费
        $postage  = 0;
        $list     = json_decode($spuInfoList, true);

        $spuIds = array_column($list,'spuId');
        $ret = SupplyService::getInstance()->getData(SupplyConst::GET_SPU_BY_SPUIDS, ['spuIdList' => $spuIds]);
        if ($ret['status'] == 200 && !empty($ret['data'])) {
            foreach($ret['data'] as $v){
                if($v['status'] == 1){
                    SupplyGoods::getInstance()->where('spu_id','in',$spuIds)->update(['status' => 1]);
                    CommonUtil::throwException(ErrorConst::PARAM_ERROR,'商品已下架');
                }
            }
        }

        $sendCity = '';
        if ($address) {
            $data = [];
            foreach ($list as $v) {
                $data[] = [
                    'quantity' => $v['quantity'],
                    'spuId'    => $v['spuId'],
                ];
            }
            $provinceRegion = SupplyService::getInstance()->getRegionByCodeOpen();
            $provinceData   = array_column($provinceRegion['data'], 'name', 'regionCode');
            $keyName        = array_search($address['province'], $provinceData);
            if ( ! empty($keyName)) {
                $cityRegion = SupplyService::getInstance()->getRegionByCodeOpen($keyName);
                $sendCity   = $cityRegion['data']['name'] ?? '';
                $cityData   = array_column($cityRegion['data'], 'name', 'regionCode');
                $keyName    = array_search($address['city'], $cityData);
            }
            $ret = SupplyService::getInstance()->freight(json_encode($data), $keyName);
            if ($ret['status'] == 200) {
                $postage = bcadd($postage, $ret['data'], 2);
            }
        }
        $discountSale = 0;
        $sellPrice    = 0;
        $info         = SupplyService::getInstance()->orderPreview($spuInfoList);
        foreach ($info as &$v) {
            if ($v['stock'] < $v['quantity']) {
                CommonUtil::throwException(ErrorConst::NO_GOODS_ERROR, ErrorConst::NO_GOODS_ERROR_MSG);
            }
            //商品总支付金额 = 价格x数量
            $sellPrice     = bcmul($v['sellPrice'], $v['quantity'], 2);
            $v['payPrice'] = $v['sellPrice'];
            // 预览的时候不需要算折扣优惠
            // $v['discountSale'] = $level_discount > 0 ? bcmul($v['payPrice'], (1 - $level_discount), 2) : 0; // 折扣金额
            // $discountSale = bcadd($discountSale, $v['discountSale'], 2);

        }
        $payPrice = bcadd($sellPrice, $postage, 2);
        $tips     = \app\api\logic\OrderLogic::getInstance()->estimatedDelivery(
            $sendCity,
            $address['city'] ?? '',
        );
        $finance = MemberService::getInstance()->finance($this->userinfo->id);
        $config= Marketing::getKeyData('marketing', 'deduction');
        return [
            'levelDiscount'      => $level_discount,
            'couponDiscountBoth' => $coupon_discount_both,
            'tips'               => $tips,
            'rows'               => $info,
            'sellPrice'          => $sellPrice,
            'payPrice'           => $payPrice - $discountSale,
            'postage'            => $postage,
            'deductionConfig'    => $config,
            'finance'            => $finance,
        ];
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function createOrder($goodsList, $addressId, $couponId, $userNote, $deduction, $option = []): array
    {
        if (empty($goodsList)) {
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, ErrorConst::PARAM_ERROR_MSG);
        }
        $address = Address::getInstance()->where('id', $addressId)->find();

        //获取商品运费
        $postage    = 0;
        $list       = json_decode($goodsList, true);
        $cityCode   = '';
        $postageArr = [];
        $skuList    = [];

        if ($address) {
            $provinceRegion = SupplyService::getInstance()->getRegionByCodeOpen();
            // var_dump($provinceRegion);exit;
            foreach ($list as $v) {
                $skuList[] = [
                    'goodsQty' => $v['quantity'],
                    'skuId'    => $v['skuId'],
                ];
                $data[] = [
                    'quantity' => $v['quantity'],
                    'spuId'    => $v['spuId'],
                ];
                $keyName  = '';
                $province = mb_substr($address['province'], 0, 2);
                foreach ($provinceRegion['data'] as $vv) {
                    if (mb_substr($vv['name'], 0, 2) == $province) {
                        $keyName = $vv['regionCode'];
                        break;
                    }
                }
                if ( ! empty($keyName)) {
                    $cityRegion = SupplyService::getInstance()->getRegionByCodeOpen($keyName);
                    foreach ($cityRegion['data'] as $vvv) {
                        if (mb_substr($vvv['name'], 0, 2) == $province) {
                            $cityCode = $vvv['regionCode'];
                            break;
                        }
                    }
                    if ( ! $cityCode) {
                        $cityData = array_column($cityRegion['data'], 'name', 'regionCode');
                        $cityCode = array_search($address['city'], $cityData);
                    }
                    $ret = SupplyService::getInstance()->freight(json_encode($data), $cityCode);
                    if ($ret['status'] == 200) {
                        $postage                 = bcadd($postage, $ret['data'], 2);
                        $postageArr[$v['spuId']] = $ret['data'];
                    }
                }
            }
        }

        [$level_discount, $coupon_discount_both] = \app\api\services\UserLevelService::getInstance()->levelDiscount(
            $this->userinfo->id
        );
        $orderNo   = getNo('SU');
        $sellPrice = 0;
        $costPrice = 0;
        $info      = SupplyService::getInstance()->orderPreview($goodsList);

        $discountSale = 0;
        // 使用优惠类型：  coupon | discount | coupon_discount | '' 空字符串表示不需要优惠
        $useSale = $option['useSale'] ?? 'unknow';
        if ($useSale == '' || $useSale == 'discount') {
            $couponId = '';
        }
        if ($useSale == 'coupon' || $useSale == '') {
            $level_discount = 0;
        }
        $orderGoods = [];
        foreach ($info as $v) {
            $sellPrice = bcmul($v['sellPrice'], $v['quantity'], 2);
            $costPrice = bcmul($v['basePrice'], $v['quantity'], 2);

            $v['discountSale'] = $level_discount > 0 ? bcmul($v['sellPrice'], (1 - $level_discount), 2) : 0; // 折扣金额

            $discountSale = bcadd($discountSale, $v['discountSale'], 2);

            $orderGoods[] = [
                'user_id'       => $this->userinfo->id,
                'order_no'      => $orderNo,
                'expire_at'     => date('Y-m-d H:i:s', strtotime('+15 minutes')),
                'postage'       => $postageArr['spuId'] ?? 0,
                'cost_price'    => $v['basePrice'],
                'sell_price'    => $v['sellPrice'],
                'pay_price'     => $v['sellPrice'] - $v['discountSale'],
                'discount_sale' => $v['discountSale'],
                'quantity'      => $v['quantity'],
                'goods_id'      => $v['goodsId'],
                'sku_id'        => $v['skuId'],
                'goods_img'     => $v['img'],
                'goods_title'   => $v['name'],
                'sku_title'     => $v['skuTitle'],
                'order_type'    => 4,
                'gxz_rate'      => $v['gxzRate'],
            ];
        }

        //省市区编码
        $areaRegion = SupplyService::getInstance()->getRegionByCodeOpen($cityCode);
        $areaData   = array_column($areaRegion['data'], 'name', 'regionFullCodes');
        if ($address['city'] == $address['country']) {
            $address['country'] = $address['street'];
        }
        $keyName = array_search($address['country'], $areaData);
        if ( ! $keyName) {
            CommonUtil::throwException(ErrorConst::NO_ADDRESS_ERROR, ErrorConst::NO_ADDRESS_ERROR_MSG);
        }
        $arr        = explode(',', $keyName);
        $newArr     = array_reverse($arr);
        $addrPath   = implode(',', $newArr);
        $payPrice   = bcadd($sellPrice, $postage, 2);
        $special_id = $option['special_id'] ?? 0;
        $data       = [
            'user_id'    => $this->userinfo->id,
            'order_no'   => $orderNo,
            'order_type' => 4,
            'postage'    => $postage,
            'cost_price' => $costPrice,
            'sell_price' => $sellPrice,
            'pay_price'  => $payPrice - $discountSale,
            'sale'       => $discountSale,
            'addr_path'  => $addrPath,
            'user_note'  => $userNote,
            'goods_list' => json_encode($skuList),
            'special_id' => (int) $special_id,
            'expire_at'  => date('Y-m-d H:i:s', strtotime('+15 minutes')),
        ];

        if ( ! empty($couponId)) {
            $couponInfo = CouponService::getInstance()->getCouponInfo($couponId, $this->userinfo->id);
            if (empty($couponInfo)) {
                CommonUtil::throwException(ErrorConst::COUPON_ERROR, ErrorConst::COUPON_ERROR_MSG);
            }

            $ret = CouponService::getInstance()->checkOrderCoupon($couponInfo, 2, $list);
            if ( ! $ret) {
                CommonUtil::throwException(
                    ErrorConst::COUPON_ERROR,
                    '优惠券使用范围受限');
            }
            [$couponMoney, $pSale, $shopSale] = CouponService::getInstance()->calCouponPrice(
                $payPrice,
                $couponId,
                $this->userinfo->id);
            // var_dump($payPrice, $couponMoney, $couponId, $this->userinfo->id);exit;
            $data['sale']      = bcsub($data['sale'], $couponMoney, 2);
            $data['pay_price'] = bcsub($data['pay_price'], $couponMoney, 2);
            $data['coupon_id'] = $couponId;

            $len               = count($orderGoods);
            $platform_sale     = number_format($couponMoney / $len, 2, '.', '');
            $platform_sale_sum = 0;
            foreach ($orderGoods as $i => &$vo) {
                // print_r($i == ($len - 1));
                if ($i == ($len - 1)) {
                    $vo['platform_sale'] = $couponMoney - $platform_sale_sum;
                } else {
                    $vo['platform_sale'] = $platform_sale;
                }
                $vo['pay_price'] -= $vo['platform_sale'];
                $platform_sale_sum += $platform_sale;
            }
        }

        if($deduction > 0){
            $config = Marketing::getKeyData('marketing', 'deduction');
            if(isset($config['status']) && $config['status'] == 1){
                Log::error("supply:sell_price=".$data['sell_price'].'supply_max:'.$config['supply_max']);
                if($data['sell_price'] >= $config['supply_max']){
                    //限制
                    if($config['supply_limit_type'] == 0){
                        //金额
                        if($config['supply_type'] == 0){
                            if($deduction > $config['supply_value']){
                                CommonUtil::throwException(ErrorConst::PARAM_ERROR, '超过最大抵扣金额');
                            }
                        }else{
                            //比例
                            if($config['supply_rate'] > 0){
                                $can = bcmul($data['sell_price'],$config['supply_rate']*0.01,2);
                                if($deduction > $can){
                                    CommonUtil::throwException(ErrorConst::PARAM_ERROR, '超过最大抵扣金额');
                                }
                            }
                        }
                    }
                    $data['pay_price'] = bcsub($data['pay_price'],$deduction,2);
                    if($data['pay_price'] < 0){
                        $data['pay_price'] = 0;
                    }
                    $data['deduction'] = $deduction;
                    foreach ($orderGoods as  &$v) {
                        $v['pay_price'] = bcsub($v['pay_price'],$deduction,2);
                    }
                }
            }

        }
        Order::getInstance()->startTrans();
        try {
            //订单
            Order::getInstance()->insert($data);

            //订单商品
            OrderGoods::getInstance()->insertAll($orderGoods);

            //订单发货地址
            $address['orderNo'] = $orderNo;
            $address            = CommonUtil::camelToUnderLine($address->toArray());
            unset($address['id'], $address['is_default'], $address['address_type'], $address['create_at'], $address['update_at']);
            OrderAddress::getInstance()->insert($address);

            if ( ! empty($couponId)) {
                CouponService::getInstance()->updateCouponInfo($couponId);
            }

        } catch (\Exception $e) {
            Order::getInstance()->rollback();
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, $e->getMessage());
        }
        Order::getInstance()->commit();

        return ['orderNo' => $orderNo];
    }
}
